﻿using System;
using System.Collections.Generic;
using System.Linq;
using Ninject;
using Ninject.Planning.Bindings;
using Ninject.Syntax;
using Reap.Common.Runtime.Dependency.Ninject.InRequestScope;

namespace Reap.Common.Runtime.Dependency.Ninject
{
	/// <summary>
	///     容器扩展类，指明作用域，绑定关键字和对象类型
	/// </summary>
	public static class ContainerManagerExtensions
	{
		/// <summary>
		///     指定作用域
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="binding"></param>
		/// <param name="lifeStyle"></param>
		/// <returns></returns>
		public static IBindingNamedWithOrOnSyntax<T> PerLifeStyle<T>(this IBindingWhenInNamedWithOrOnSyntax<T> binding,
			ComponentLifeStyle lifeStyle)
		{
			switch (lifeStyle)
			{
				case ComponentLifeStyle.Singleton:
					return binding.InSingletonScope();
				case ComponentLifeStyle.InThreadScope:
					return binding.InThreadScope();
				case ComponentLifeStyle.InRequestScope:
					return binding.InRequestScope();
				case ComponentLifeStyle.Transient:
				default:
					return binding.InTransientScope();
			}
		}

		/// <summary>
		///     关键字映射
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="binding"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public static IBindingSyntax MapKey<T>(this IBindingNamedSyntax<T> binding, string key)
		{
			IBindingSyntax bindingSyntax = binding;
			if (!string.IsNullOrEmpty(key))
			{
				bindingSyntax = binding.Named(key);
			}
			return bindingSyntax;
		}

		/// <summary>
		///     替换已经存在的类型
		/// </summary>
		/// <param name="bindingInSyntax"></param>
		/// <param name="type"></param>
		public static void ReplaceExisting(this IBindingSyntax bindingInSyntax, Type type)
		{
			IKernel kernel = bindingInSyntax.Kernel;
			IEnumerable<IBinding> bindingsToRemove =
				kernel.GetBindings(type)
					.Where(
						b => string.Equals(b.Metadata.Name, bindingInSyntax.BindingConfiguration.Metadata.Name, StringComparison.Ordinal));
			foreach (IBinding bindingToMove in bindingsToRemove)
			{
				kernel.RemoveBinding(bindingToMove);
			}
			var binding = new Binding(type, bindingInSyntax.BindingConfiguration);
			kernel.AddBinding(binding);
		}
	}
}